Friday, March 1, 2013

Ordering a QuerySet based on a latest child models field

Lets assume I want to show a list of runners ordered by their latest sprint time.

class Runner(models.Model):
    name = models.CharField(max_length=255)

class Sprint(models.Model):
    runner = models.ForeignKey(Runner)
    time = models.PositiveIntegerField()
    created = models.DateTimeField(auto_now_add=True)


This is a quick sketch of what I would do in SQL:

SELECT runner.id, runner.name, sprint.time
FROM runner
LEFT JOIN sprint ON (sprint.runner_id = runner.id)
WHERE 
  sprint.id = (
    SELECT sprint_inner.id
    FROM sprint as sprint_inner
    WHERE sprint_inner.runner_id = runner.id
    ORDER BY sprint_inner.created DESC
    LIMIT 1
  )
  OR sprint.id = NULL
ORDER BY sprint.time ASC


The Django QuerySet documentation states:

It is permissible to specify a multi-valued field to order the results by (for example, a ManyToManyField field). Normally this won't be a sensible thing to do and it's really an advanced usage feature. However, if you know that your queryset's filtering or available data implies that there will only be one ordering piece of data for each of the main items you are selecting, the ordering may well be exactly what you want to do. Use ordering on multi-valued fields with care and make sure the results are what you expect.
 

I guess I need to apply some filter here, but I'm not sure what exactly Django expects...

One note because it is not obvious in this example: the Runner table will have several hundred entries, the sprints will also have several hundreds and in some later days probably several thousand entries. The data will be displayed in a paginated view, so sorting in Python is not an option.

The only other possibility I see is writing the SQL myself, but I'd like to avoid this at all cost.

PS: This is a copy of my StackOverflow question: http://stackoverflow.com/q/15154863/360593

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

No comments:

Post a Comment