Reputation: 1663
I have two Django models that look like this:
class Team(models.Model):
name = models.CharField(max_length=30)
...
class Game(models.Model):
teamA = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamA')
teamB = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamB')
....
Game
model has 2 foreign keys to Team
model.
Of course, it is not possible for a team to play against itself, so I would like to prevent teamA and teamB from referring to the same record in DB.
So you can't create a game like this:
Game.objects.create(teamA=ChicagoBulls, teamB=ChicagoBulls)
What is the best way to do this?
Upvotes: 1
Views: 57
Reputation: 476719
You can implement a constraint in the .clean()
method [Django-doc], and also at the database level with a CheckConstraint
[Django-doc] (not all databases will however enforce this):
from django.core.exceptions import ValidationError
from django.db.models import F, Q
class Game(models.Model):
teamA = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamA')
teamB = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamB')
# …
def clean(self, *args, **kwargs):
if self.teamA_id == self.teamB_id:
raise ValidationError('The two teams should be different')
super().clean(*args, **kwargs)
class Meta:
constraints = [
models.CheckConstraint(
check=~Q(teamA=F('teamB')),
name='different_teams'
)
]
The .clean()
method is not checked when you create an object with the model layer. It is however validated when you create a Game
through a ModelForm
[Django-doc].
You probably also might want to make the name
of the Team
unique, such that there can not be two teams with the same name:
class Team(models.Model):
name = models.CharField(max_length=30, unique=True)
# …
Upvotes: 2