Get models ordered by an attribute that belongs to its OneToOne model
<p>Let's say there is one model named <code>User</code> and the other named <code>Pet</code> which has a <code>OneToOne</code> relationship with <code>User</code>, the <code>Pet</code> model has an attribute <code>age</code>, how to get the ten <code>User</code> that owns the top ten <code>oldest</code> dog?</p>

<pre><code>class User(models.Model):
     name = models.CharField(max_length=50, null=False, blank=False)

class Pet(models.Model):
     name = models.CharField(max_length=50, null=False, blank=False)
     owner = models.OneToOneField(User, on_delete=models.CASCADE)
     age = models.IntegerField(null=False)
</code></pre>

<hr>

<p>In <code>User</code>, there is an attribute <code>friends</code> that has a <code>ManyToMany</code> relationship with <code>User</code>, how to get the ten <code>friends</code> of <code>User Tom</code> that owns the top ten <code>oldest</code> dog?</p>

<pre><code>class User(models.Model):
     name = models.CharField(max_length=50, null=False, blank=False)
     friends = models.ManyToManyField(self, ...)

class Pet(models.Model):
     name = models.CharField(max_length=50, null=False, blank=False)
     owner = models.OneToOneField(User, on_delete=models.CASCADE)
     age = models.IntegerField(null=False)
</code></pre>

<p>Another solution (alternative to <code>order_by</code>) is using <code>nlargest</code> function of <code>heapq</code> module, this might be better if you already have <code>friends</code> list (tom's friends in this case) with a large number of items (I mean from performance perspective).</p>

<pre><code>import heapq

heapq.nlargest(
    10,
    User.objects.get(name='Tom').friends.all(),
    key=lambda f: f.pet.age
)
</code></pre>

<p><strong>Note:</strong> You have also <code>nsmallest</code> function that you can use to get the youngest pets.</p>

python django python-3.x