Mike Doudkin
Mike Doudkin

Reputation: 638

Get related objects from a queryset, preserving the ordering

I have a model, which looks something like this:

class Agent(models.Model):
    class Meta:
        ordering = ['first_name', 'last_name', ]
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    ... some other fields ...

class Point(models.Model):
    agent = models.ForeignKey(Agent)
    ... some other fields ...

When I select some points I want them to be ordered by agent names, like this:

points = Point.objects.filter(...smth...).order_by(-agent)

So the resulting queryset is ordered by agent names, from Z to A

or

points = Point.objects.filter(...smth...).order_by(agent)

or even without ordering

The question is: How to get a queryset or a list of unique agent objects from points queryset, preserving the ordering?

Preferrably, without any more order_by() statements, because the view may or may not be explicitly aware of ordering type

Something like set(points.values_list('agent', flat=True)), but with objects instead of pk-s?

Upvotes: 1

Views: 566

Answers (3)

user2390182
user2390182

Reputation: 73450

You can use your own idea and nest it like so (where points is any QuerySet of Point):

Agent.objects.filter(id__in=points.values_list('agent', flat=True))

Django ORM will translate this into a single db query. This should have Agent's default order. In order to preserve the agent order in points, you could do:

[p.agent for p in points.distinct('agent')]

This workaround, obviously, is not a queryset and distinct with field arguments is only supported in Postgres.

Upvotes: 1

Parag Tyagi
Parag Tyagi

Reputation: 8960

This should work.

Agent.objects.filter(id__in=Point.objects.values_list('agent_id', flat=True)).order_by('-first_name')

Update:

Point.objects.filter(agent_id__in=Agent.objects.values_list('id', flat=True)).distinct('agent').order_by('-agent__first_name')

Upvotes: 0

falsetru
falsetru

Reputation: 368894

Use Agent objects manager, and QuerySet.distinct to get unique agents:

Agent.objects.filter(point__condition=...).distinct().order_by('-pk')

NOTE: condition=... should be adjusted to point__condition=....

Upvotes: 0

Related Questions