Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enforce different values in multiple ForeignKey fields for Django

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?

like image 547
jhc Avatar asked Jan 30 '16 00:01

jhc


People also ask

How does Django implement one to many relationship?

To handle One-To-Many relationships in Django you need to use ForeignKey . The current structure in your example allows each Dude to have one number, and each number to belong to multiple Dudes (same with Business).

How does ForeignKey work in Django?

ForeignKey is a Django ORM field-to-column mapping for creating and working with relationships between tables in relational databases. ForeignKey is defined within the django.

What is Onetoone field in Django?

This field can be useful as a primary key of an object if that object extends another object in some way. For example – a model Car has one-to-one relationship with a model Vehicle, i.e. a car is a vehicle. One-to-one relations are defined using OneToOneField field of django.

How do I merge two Django models?

1 Answer. Show activity on this post. In your models Device and History models are related with a foreign key from History to DeviceModel, this mean when you have a History object you can retrieve the Device model related to it, and viceversa (if you have a Device you can get its History).


2 Answers

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')
    ]
like image 167
Ali Shekari Avatar answered Oct 17 '22 03:10

Ali Shekari


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.

like image 35
Derek Kwok Avatar answered Oct 17 '22 01:10

Derek Kwok