How to restrict a foreign key form field based on previously selected field?

To preface this I know that there are some previous posts about this but the answers refer to using 3rd party packages and I was wondering if there is a solution using vanilla Django as these posts are a few years old.

I am creating an music based app which has models for Artists, Albums and Tracks. What I'd like to do is when adding new tracks in the admin panel, if I select an Artist in the form then the Album choices are restricted to ones by that Artist but can't find anyway to make this work, at first I thought I may have been able to use "__" to make the relation, like in list_filter for the model admin but that didn't work.

I added the artist field to the Track while trying to find a solution for this but am unsure if it is required.

I am yet to develop most of the views for this app, this is currently just for the admin panel to add new tracks.

class Artist(models.Model):
    name = models.CharField(max_length=100, verbose_name="Artist")
    genre = models.CharField(max_length=100)
    country = CountryField(blank_label="(select country)")
    is_approved = models.BooleanField(default=False)

    def __str__(self):
        return self.name


class Album(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    name = models.CharField(max_length=100, verbose_name="Album")
    release_date = models.DateField()
    is_approved = models.BooleanField(default=False)

    def __str__(self):
        return self.name


class Track(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE, verbose_name="Artist")
    album = models.ForeignKey(Album, on_delete=models.CASCADE, verbose_name="Album")
    listing_num = models.IntegerField(default=0)
    title = models.CharField(max_length=100)
    duration = models.CharField(max_length=10)
    spotify_link = models.CharField(max_length=256)
    apple_music_link = models.CharField(max_length=256)
    is_approved = models.BooleanField(default=False)

    def __str__(self):
        return self.title


class TrackForm(ModelForm):
    class Meta:
        model = Track
        fields = [
            "artist",
            "album",
            "listing_num",
            "title",
            "duration",
            "spotify_link",
            "apple_music_link",
        ]

Here is the code for TrackAdmin:

class TrackAdmin(admin.ModelAdmin):
    model = Track
    list_display = [
        "artist",
        "album",
        "listing_num",
        "title",
        "duration",
        "is_approved",
    ]
    list_filter = ["album__name", "artist__name", "is_approved"]
Back to Top