Tuesday, 10 September 2013

Django 1.4: prefect_related with custom model manager and order_by?

Django 1.4: prefect_related with custom model manager and order_by?

This is a long shot question (doesn't seem like it is possible from the
Django docs, but thought I'd ask just to see if anyone has any ideas).
Note: I'm using Django 1.4.
I want to use a custom model manager on a prefetch_related() query. Then,
on top of that, I want to order the prefetched results in a certain way.
To put it in simplified code, I have the following models (note:
Participant model excluded from code because it is irrelevant):
class GoalParticipant(models.Model):
"""Many-to-many model between Goal and Participant models."""
participant = models.ForeignKey(
'Participant', related_name='goal_participants')
goal = models.ForeignKey('Goal', related_name='goal_participants')
active = models.BooleanField(default=True)
class Goal(models.Model):
name = models.CharField(max_length=50)
progress = models.IntegerField()
active = models.BooleanField(default=True)
class Milestone(models.Model):
name = models.CharField(max_length=50)
progress = models.IntegerField()
goal = models.ForeignKey('Goal', related_name='milestones')
active = models.BooleanField(default=True)
From here, my page controller gets a GoalParticipant Id value (called,
say, pid). I want to display all of the goals and milestones for that ID.
So something like this would work normally:
GoalParticipant.objects.filter(participant=pid).select_related(
).prefetch_related('goal__milestones')
Here are the two wrinkles:
1: Custom Model Manager
All of my classes have custom model managers, like this:
objects = ActiveManager()
all_objects = models.Manager()
The ActiveManager runs .filter(active=True) on the queryset. This is for
convenience, so that I can easily just say .objects by default and have
the active filter thrown in. Occasionally, though, I need to display all
of the objects, not just active ones. So I tried this:
GoalParticipant.all_objects.filter(participant=pid).select_related(
).prefetch_related('goal__milestones')
This gives me all of the goal_participants and all of the goals, but still
restricts to only active milestones. Is there a way to force
prefetch_related to use the all_objects model manager?
2: Custom Ordering for Milestones
Users can actually order the goals / milestones by either name or progress
in the UI, and the ordering should be consistent. For example, if the
goals are ordered by progress, the milestones should also be ordered by
progress. So, say I have a var called ordering with the correct ordering,
I could do this:
GoalParticipant.objects.filter(participant=pid).select_related(
).order_by(ordering).prefetch_related('goal__milestones')
This orders the goals correctly, but there does not seem to be any way to
force the milestones to order in the same way. Is there a way to do this?
Thanks in advance for your help and let me know if I can clarify anything.

No comments:

Post a Comment