14

I have the following models in Django:

from django.db import models

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


class Match(models.Model):                                                      
    team_home = models.ForeignKey(Team)                                                      
    team_visitors = models.ForeignKey(Team)                                                       
    league = models.CharField(max_length=200)                                                      
    date_played = models.DateField()  

The idea is to be able to have a 'Match' object which has two teams who played a match of some game. It would be very odd that a team be playing itself. How can I guarantee that team_home is not equal to team_visitors?

SO Stinks
  • 3,258
  • 4
  • 32
  • 37
jhc
  • 1,739
  • 3
  • 21
  • 46

3 Answers3

19

You can use this CheckConstraint in class Meta of your django model:

class Meta:
    constraints = [
        models.CheckConstraint(
            check=~Q(team_home=F('team_visitors')),
            name='team_home_and_team_visitors_can_not_be_equal')
    ]
Cesar Canassa
  • 18,659
  • 11
  • 66
  • 69
Ali Shekari
  • 262
  • 4
  • 12
7

This cannot be done through pure Django. There's a ticket for adding CHECK constraints: https://code.djangoproject.com/ticket/11964

To ensure the situation where team_home == team_visitors never happens, you will need to add a custom constraint to the table which is database dependent. As an example, in MySQL and PostgresQL:

alter table myapp_match add constraint match_teams_not_equal check (team_home_id <> team_visitors_id);

This will cause the database to raise an integrity error when a save happens. Note that there are also databases where you cannot implement such a constraint.

You can partially ensure that team_home != team_visitors by overriding the save method:

class Match(models.Model):
    ....
    def save(self, *args, **kwargs):
        if self.team_home == self.team_visitors:
            raise Exception('attempted to create a match object where team_home == team_visitors')
        super(Match, self).save(*args, **kwargs)

However, someone can modify the database directly, or use update queryset in Django and you can still end up with Match objects where team_home == team_visitor.

Derek Kwok
  • 12,768
  • 6
  • 38
  • 58
-4

I believe you can use the unique_together property of the Meta class: unique_together

class Match(models.Model):
    ...
    class Meta:
        unique_together = ("team_home", "team_visitors")
camomilk
  • 763
  • 1
  • 7
  • 15
  • Thanks! Read the documentation, seems right! Thanks alot. – jhc Jan 30 '16 at 01:21
  • 15
    This is wrong, it will **not** prevent the creation of a `Match` object where `team_home == team_visitors`. The `unique_together` constraint will ensure that for any two teams, they can only have a single match - since the combination of `team_home`, `team_visitor` must be unique. – Derek Kwok Jan 30 '16 at 01:53