schinckel / django-computed-field

ComputedField() for django
MIT License
26 stars 2 forks source link

`Models aren't loaded yet.` when annotating with models.Subquery #6

Open olivierdalang opened 5 years ago

olivierdalang commented 5 years ago

Hi !

Thanks for the great work ! A great addition to Django !

I've an issue that is probably a relatively common deal breaker.

When using models.Subquery in the annotation, I get an Models aren't loaded yet. exception .

I guess this could be solved by allowing to wrap the expression in a callable, so that it could be evaluated lazily.

Here's the (simplified) code I'm trying to adapt to the library :

class Work(models.Model):
    task = models.ForeignKey("Task", on_delete=models.PROTECT)
    date = models.DateField()
    hours_done = models.FloatField()

class TaskManager(models.Manager):
    def get_queryset(self):
        qs = super().get_queryset()
        qs = qs.annotate(total_hours_done=models.Subquery(
            Work.objects.filter(task=OuterRef("pk"))
            .values("task")
            .order_by()
            .annotate(total=Sum("hours_done"))
            .values("total"),
            output_field=models.FloatField(),
        ))
        return qs

class Task(models.Model):
    objects = TaskManager()
    name = models.CharField(max_length=255)

I adapted it like this :

class Task(models.Model):
    name = models.CharField(max_length=255)
    total_hours_done = ComputedField(
        models.Subquery(
            Work.objects.filter(task=OuterRef("pk"))
            .values("task")
            .order_by()
            .annotate(total=Sum("hours_done"))
            .values("total"),
            output_field=models.FloatField(),
        )
    )