12đź‘Ť
Here is another way to tackle this problem.
Instead of creating a circular dependency, I created an additional table that stores the relationship between players and teams. So in the end it looks like this:
class Team(Model):
name = CharField(max_length=50)
def get_captain(self):
return PlayerRole.objects.get(team=self).player
class Player(Model):
first_name = CharField(max_length=50)
last_name = CharField(max_length=50, blank=True)
def get_team(self):
return PlayerRole.objects.get(player=self).team
PLAYER_ROLES = (
("Regular", "Regular"),
("Captain", "Captain")
)
class PlayerRole(Model):
player = OneToOneField(Player, primary_key=True)
team = ForeignKey(Team, null=True)
role = CharField(max_length=20, choices=PLAYER_ROLES, default=PLAYER_ROLES[0][0])
class Meta:
unique_together = ("player", "team")
It might be slightly less efficient in terms of storage than the suggested workaround, but it avoids the circular dependency and keeps the DB structure clean and clear.
Comments are welcome.
58đź‘Ť
as you can see in the docs, for exactly this reason it is possible to specify the foreign model as a string.
team = models.ForeignKey('Team')
- [Django]-How to get Gunicorn to use Python 3 instead of Python 2 (502 Bad Gateway)
- [Django]-Django model – set default charfield in lowercase
- [Django]-How do I execute raw SQL in a django migration
12đź‘Ť
You could use the full application label in the foreign key to the model not yet defined, and use related_name to avoid name conflict:
class Team(models.Model):
captain = models.ForeignKey('myapp.Player', related_name="team_captain")
class Player(models.Model):
team = models.ForeignKey(Team)
- [Django]-Django: permission denied when trying to access database after restore (migration)
- [Django]-Django: Get current user in model save
- [Django]-Django rest framework serializing many to many field
5đź‘Ť
This is what you were looking for:
class Team(models.Model):
name = models.CharField()
captain = models.ForeignKey('Player')
class Player(models.Model):
name = models.CharField()
team = models.ForeignKey(Team)
- [Django]-Turn off automatic pagination of Django Rest Framework ModelViewSet
- [Django]-Annotate with latest related object in Django
- [Django]-Testing admin.ModelAdmin in django
1đź‘Ť
Neither of the answers here are really that great – creating circular references is never a good idea. Imagine if your database crashed and you had to create it from scratch – how would you create player before team is created, and vice versa? Look a question here: ForeignKey field with primary relationship one I asked a few days ago. Put a Boolean on Player that specifies the captain, and put some pre-save hooks that validate every team must have one-and-only-one captain.
- [Django]-Django: Difference between using server through manage.py and other servers like gunicorn etc. Which is better?
- [Django]-Reload django object from database
- [Django]-Is it possible to decorate include(…) in django urls with login_required?
1đź‘Ť
Have a Captain table that has player/team columns along with your other tables, and make captain a method of Team:
class Team(models.Model):
name = models.CharField()
def captain(self):
[search Captain table]
return thePlayer
class Player(models.Model):
name = models.CharField()
team = models.ForeignKey(Team)
class Captain(models.Model):
player = models.ForeignKey(Player)
team = models.ForeignKey(Team)
You’d have to check that you never have more than one captain in the same team though… But you don’t have any circular references that way. You could also end up with a captain who isn’t in the team he’s flagged as captain of. So there’s a few gotchas this way.
- [Django]-Django Class Based View for both Create and Update
- [Django]-Automatically import models on Django shell launch
- [Django]-What is PyMySQL and how does it differ from MySQLdb? Can it affect Django deployment?
1đź‘Ť
Although there is nothing wrong with having two references to the same model, perhaps there is a better way to solve this particular problem.
Add a boolean to the Team
model to identify a player + team combination as captain:
class Team(models.Model):
player = models.ForeignKey(Player)
name = models.CharField(max_length=50)
is_captain = models.BooleanField(default=False)
To search for a team’s captain:
Team.objects.filter(is_captain=True)
Personally I don’t like this method because the search semantics don’t make sense (ie, a “team” is not a “captain”).
The other approach is to identify each player’s position:
class Player(models.Model):
name = models.CharField(max_length=50)
position = models.IntegerField(choices=((1,'Captain'),(2,'Goal Keeper'))
jersey = models.IntegerField()
def is_captain(self):
return self.position == 1
class Team(models.Model):
name = models.CharField(max_length=50)
player = models.ForeignKey(Player)
def get_captain(self):
return self.player if self.player.position == 1 else None
This makes a bit more sense when you search:
Player.objects.filter(position=1)
(return all captains)
Team.objects.get(pk=1).get_captain()
(return the captain for this team)
In either case, however you have to do some pre save checks to make sure there is only one player for a particular position.
- [Django]-Django 1.7 – How do I suppress "(1_6.W001) Some project unittests may not execute as expected."?
- [Django]-Warning: cannot find svn location for distribute==0.6.16dev-r0
- [Django]-Django is "unable to open database file"
0đź‘Ť
Now can be used the AppConfig feature to import models:
Retailer = apps.get_model('retailers', 'Retailer')
retailer = Retailer.objects.get(id=id)
- [Django]-Django form fails validation on a unique field
- [Django]-Django: templatedoesnotexist gis/admin/openlayers.html
- [Django]-Apache + mod_wsgi vs nginx + gunicorn