2

I got a list of Player instances (a team) for example team = [player1, player2, player3]

How do I "get_or_create" the Team containing these and only these three players with one query?

These are my django models:

class Player(models.Model):
    name = models.CharField(max_length=100)

class Team(models.Model):
    players = models.ManyToManyField(Player)
kissgyorgy
  • 2,947
  • 2
  • 32
  • 54

1 Answers1

1

Documentation says that get_or_create is a shortcut for:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

So I would adapt it to your use case as follows:

from django.db.models import Q, Count
import operator

players = [player1, player2, player3]

team = Team.objects
    .filter(reduce(
         operator.and_,
         [Q(players=player) for player in players]
    ))
    .annotate(count=Count('players'))
    .filter(count=len(players))

# Note that this ^ returns a QuerySet. With your posted model there
# might exist several teams with exactly the same players.  

if not team.exists():
    team = Team.objects.create()
    team.players.add(*players)

Slightly more complex but the workflow is the same:

  • Query for existence.
  • If not existent, create.
Adrián
  • 6,135
  • 1
  • 27
  • 49
  • I accepted your answer, however I noticed a small mistake. `team.players.add()` doesn't accept an iterable, but multiple arguments, so it should be `team.players.add(*players)` using python's [unpacking feature](http://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists). See it [in django documentation](https://docs.djangoproject.com/en/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager.add). – kissgyorgy Sep 03 '13 at 17:26