Annotate queryset with prefetched model instance

Let’s say I have the following models:

class Practice(Model):
    # ...

class PracticeAssignee(Model):
    practice = ForeignKey(Practice, related_name="assignees")
    user = ForeignKey(User)
    active = BooleanField()

class User(Model):
    # ...

I am trying to create a queryset where each practice has a field assignee_user which contains the full model instance of the active assignee user (I realize there is nothing preventing multiple active assignee users at once, but let’s say returning the first one is fine).

This is what I’ve tried:

Practice.objects.all().prefetch_related(Prefetch("assignees__user", PracticeAssignee.models.filter(active=True)).annotate(assignee_user=F("assignees__user"))

However, this only annotates the queryset with the id of the user. How do I make it so I get the whole model instance available as a prefetched field inside of the practice?

You don’t.

You access the related models using the “attribute notation” (the ‘.’) to follow the relationships.

For example, if you have an instance of Practice named practice, then practice.assignees.all() is your set of related PracticeAssignee.

But you don’t need to use “all” here. As a related object manager, you can use filter.
practice.assignees.filter(active=True) returns all PracticeAssignee where active == True.

You just want the first such entry?


Now, you want the related user object to that?


The prefetch_related function is only a performance enhancement. It does not change how you use the models.

I understand that, but the thing is I’m passing the entries of that queryset to a DRF model serializer, and I would like that serializer to directly have an assignee_user field on it to embed the user in the practice object serialization.

If I add that field to the serializer, it’s going to try and access a same-named field on the model. As of now, what I did does in fact work, but the assignee_user has the id of the user as its serialized value. I figured if there was a way I could prefetch the related object and assign it as a field to the practice object, then the serializer would be able to use that for nested serialization.

How would you tackle this issue? The only thing I can thing of right now would be to define a property on the practice model. That property could use the prefetched list of assignees to return the first one, and that should be a model instance instead of just an id.

I wouldn’t try to “flatten” the serialized format. I’d define my data structure such that what I return is an accurate representation of the data. The assignees key within the serialized Practice instance would be a nested instance of the PracticeAssignee model.