Artist, solo and in multiple bands, how to get all that artists albums?

I’m working on an app for my music collection. Two of the models are Artist and Album.

I have a foreign key to Artist from Album. I have generic list views which work well for most of my purposes. I also have Detail Views for some things. For example, I do a search for Neil Young, and all of the albums I listed him as artist show up in an Artist detail view. But I also have albums where the Artist is Neil Young & Crazy Horse, or Neil Young and the Stray Gators. I’m wondering if there is a way to create a view that could show albums by all of these artists, anyone with Neil Young’s name in it. There are other artists that I would like to that for also.

Relevant code is:
Models:

class Artist(models.Model):
    """Model representing an Artist"""

    ArtistType = models.TextChoices("ArtistType", "Band Composer Musician Orchestra")
    artist_type = models.CharField(
        blank=True, choices=ArtistType.choices, max_length=100
    )
    # for Band, Orchestra
    name = models.CharField(max_length=100, null=True, blank=True, default="")
    # for Musician, Composer
    first_name = models.CharField(max_length=100, null=True, blank=True, default="")

    last_name = models.CharField(max_length=100, null=True, blank=True, default="")
    slug = models.SlugField(unique=True)
    artist_wiki = models.URLField(blank=True, null=True)


class Album(models.Model):
    """Model representing an Album."""

    # TODO - try using ManyToMany relationship for Artist

    title = models.CharField(max_length=150)
    slug = models.SlugField(max_length=150, unique=False)
    artist = models.ForeignKey(
        Artist, blank=True, null=True, default="", on_delete=models.CASCADE
    )

Artist Detail View:

class ArtistDetailView(generic.DetailView):
    """View to show details of an Artist."""

    model = Artist
    paginate_by = 15

artist_detail.html:

{% for album in artist.album_set.all %}
			<div class="card pt-4 pb-2 mb-2">
				<a href="{{ album.get_absolute_url }}" 
					class="link-offset-2 link-underline-opacity-25 link-underline-opacity-75-hover">
					<img src="{{ album.cover_image.url }}"
						alt="cover" class="rounded img-fluid" ></a>
					
				<div class="card-body text-center">
					<h6 class="card-title">{{album.title}}</h6>
				</div>
				
				<div class="card-footer text-center">
					<h6 style="font-size:.8rem; color:grey;">{{album.media_type}}</h6>
					<h6 style="font-size:.1srem; color:#A9A9A9;">{{album.release_year}}</h6>
				</div>
			</div>
{% endfor %}

I guess what I’m asking is would I need to do a many-to-many relationship between artist | album, or another model to do that, or is there a way to create a query that can do what I’m hoping for?

I’m just a hobbyist but having fun trying things out.

Ideally, yes, you need to change your models, so that an Album can have several Artists. So, instead of this in Album:

artist = models.ForeignKey(
    Artist, blank=True, null=True, default="", on_delete=models.CASCADE
)

(One note on the above – you probably want default=None instead of default="".)

You’d do:

artists = models.ManyToManyField(
    Artist, blank=True, null=True, default=None, on_delete=models.CASCADE, related_name="albums"
)

Then if you’ve got one Artist you can get all the Albums they’re associated with:

artist.album_set.all()

Or, because of the related_name:

artist.albums.all()

Thanks for your help philgyford. I figured I’d have to do it that way.

After changing the Album model it took some tweaking in the templates and views and it’s now doing what I want, mostly. Looks a little strange on the album cards but I can live with that.

Now I need to figure out how to get pagination working in the ArtistDetailView and template.

Again, thanks.