Franek Madej
Franek Madej

Reputation: 1179

Unique Combination of ManyToMany

I'm trying to create a unique Availability status for Player on given Hour. Here goes the code:

class Player(models.Model):
  first_name = models.CharField(max_length=200)
  last_name = models.CharField(max_length=200)

class Hour(models.Model):
  date = models.DateTimeField()
  players = models.ManyToManyField(Player, blank=True,
                                   through='Availability')

class Availability(models.Model):
  player = models.ForeignKey(Player, on_delete=models.CASCADE)
  hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
  available = models.BooleanField()

My problem is that it's currently possible to add same Availability few times - I want to programatically limit it to just one per combination.

Thanks in advance!

Upvotes: 3

Views: 4196

Answers (2)

Oded Har-Tal
Oded Har-Tal

Reputation: 163

You can have the unique_together on the "through" table (in your case the Avaliability Table)

class Availability(models.Model):
  player = models.ForeignKey(Player, on_delete=models.CASCADE)
  hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
  available = models.BooleanField()  
  class Meta:
    unique_together = (('player','hour'),)

And then use the get_or_create for adding/modifying:

 obj,created = Availability.objects.get_or_create(hour=hour,player=player)

Upvotes: 8

Franek Madej
Franek Madej

Reputation: 1179

I've worked around it modifying save() for Availability:

def save(self, *args, **kwargs):
    if self.pk is None:
        combination = Availability.objects.filter(player=self.player,
                                                  hour=self.hour).first()
        if combination:
            self.pk = combination.pk
    super(Availability, self).save(*args, **kwargs)

Upvotes: 1

Related Questions