I have two models, Position and Player, for a baseball site. Positions are named pitcher, catcher, first base, second base, third base, etc.
class Position(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField()
class Player(models.Model):
name = models.CharField(max_length=300)
slug = models.SlugField()
position = models.ForeignKey(Position)
Is there a way to make one query to return players in a specific order? For example, I'd like to do something like:
Player.objects.all().order_by(position=('first base', 'second base', 'third base', 'pitcher', 'catcher',))
This will return all players sorting them by the position field in the specified order of first base, second base, third base, pitcher, catcher, etc.
You can do this in python using sorted()
:
order = ['first base', 'second base', 'third base', 'pitcher', 'catcher']
players = sorted(Player.objects.all(), key = lambda p: order.index(p.position.name))
Also see these related topics:
- Custom ordering in Django
- Django custom order_by
I would recommend adding another field to the Position model and retrieve the results ordering by this field.
class Position(models.Model):
order = models.IntegerField()
name = models.CharField(max_length=100)
slug = models.SlugField()
class Meta:
ordering = ['order']
then, when you create a new position field, you set the order of it. When you need them you just do:
Position.objects.all()
Then they will be ordered.
EDIT:
As @AndrewGorcester stated, add unique=True to the order attribute to avoid programming mistakes(in case you add the same order to two different positions), looking like this:
order = models.IntegerField(unique=True)
I have a long table of profiles and sometimes need to preview one of them, so idea was to load this profile from DRF in the first chunk of data, here how it was solved:
from django.db.models import Case, When, BooleanField
Profile.objects.all().annotate(is_preview_profile=Case(When(id__exact=preview_profile_id, then=1), default=0, output_field=BooleanField())).order_by('-is_preview_profile')
More information can be found here:
https://docs.djangoproject.com/en/1.10/ref/models/conditional-expressions/#case
If you do not want to add another field to track ordering, you can override the default id
field to not be auto-assigned, and make sure that you add positions with IDs that correspond to their ordering.
id = models.PositiveIntegerField()
class Meta:
ordering = ['id']
Now you can do this:
Player.objects.all().order_by('position_id')