Search code examples
pythondjangomany-to-manymanytomanyfield

Django admin, limiting what data is being displayed inside a ManyToManyField


i have 3 models Team, Player and Fixture.

Fixture

class Fixture(models.Model):
    """(Fixture description)"""
    home = models.ForeignKey(Team, related_name="home_games")
    away = models.ForeignKey(Team, related_name="away_games")
    home_players = models.ManyToManyField(Player, related_name="home_games")
    away_players = models.ManyToManyField(Player, related_name="away_games")

class Player(models.Model):
    """(Player description)"""
    surname = models.CharField(blank=True, max_length=255)
    forename = models.CharField(blank=True, max_length=255)
    number = models.IntegerField(blank=True, null=True)
    team = models.ForeignKey(Team, related_name="players")

class Team(models.Model):
    """(Team description)"""
    name = models.CharField(blank=True, max_length=255)
    location = models.CharField(blank=True, max_length=255) 

As you can see a player belongs to a team. The Fixture as a home_team, away_team, home_players and away_players. Now, within the admin, under fixtures the "home_players" is listing ALL players, from all teams.

I'm kind of new to the django admin application, but how would i just show the home_players belonging to the home_team and the away_players belonging to the away_teams?

Thanks


Solution

  • To have your away_players field automatically update itself as you select the home or away team you'd need to use JavasScript.

    1. Listen for change event on away_team
    2. Send a view the selection and have it return a new list to populate your away_players field. (check get_urls for where this code might live)

    It's definitely not supported out of the box.

    Normally to filter the results on a m2m field or foreign key, you can use formfield_for_manytomany, but it doesn't have access to the object being edited so I don't think it's possible through this method.

    I think the easiest solution is to make the form 2 stage:

    1. Fill in home/away fields
    2. Save model
    3. Fill in home/away players

    You could also override the admin add view to only show the first two fields at first.

    class MyForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super(MyForm, self).__init__(*args, **kwargs)
            # make sure we're editing a saved model
            if self.instance.id:
                self.fields['home_players'].queryset = Player.objects.filter(team=self.instance.home)
                self.fields['away_players'].queryset = Player.objects.filter(team=self.instance.away)
    
        class Meta:
            model = Fixture
    
    
    class MyAdmin(admin.ModelAdmin):
        form = MyForm