Home > database >  Is there any method to join one level past a related_name?
Is there any method to join one level past a related_name?

Time:04-17

I'm repeatedly running into a data situation that I feel django probably has a shortcut for, but I can't find it...

I want to access a model one relationship beyond a queryset I selected via a related_name. It feels like there should be a one-liner for this, but the best I've figured out is:

for p in team.players:
   do_whatever(p.user.email)

Using select_related will precache the data, but won't actually give it to me in a usuable form.

team.players.select_related('user')  # still returns queryset of Players, not Users

It just seems like there should be some way for me to get a query_set of the associated users via one call. Something like annotate:

users = team.players.annotate('user')   # doesn't work

Is there any method that does what I'm looking for? Or is the "for - in" loop the only way to go?

The basics of my classes (greatly simplified):

class Team(models.Model):
   name = models.CharField()

class Player(models.Model):
   team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="players")
   user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="players")
   captain = models.BooleanField()

Is there any one-liner or optimization beyond doing a select_related followed by a for-in?

CodePudding user response:

You can .filter(…) [Django-doc] with:

User.objects.filter(players__team=team)

This will retrieve all the Users for which there is a Player object that refers to the team. If a User can be part of the team multiple times, you can use .distinct() [Django-doc] to retrieve each User at most once:

User.objects.filter(players__team=team).distinct()
  • Related