Great start, but, as you've guessed, you've got a little too much redundancy in your models. I would offer the following tips:
1) Don't use ManyToManyField
as much.
ManyToMany should be used where each model is related to many of the other. This isn't really the case for some of your models. For example, while each Album
has many Tracks
, the reverse probably isn't true; each Track
belongs to one, and only one, Album
. "Smells Like Teen Spirit" is a Track
on the Album
"Nevermind", but it's not a Track
on any other Album
. Thus, you should use a ForeignKey
instead.
class Track(models.Model):
track_name = models.CharField(max_length=200, null=False, blank=False)
album_name = models.ForeignKey(Album)
An exception here would be if a Track
actually would be on multiple Albums
, i.e. if it was also on a "Greatest Hits" Album
or something in addition to "Nevermind".
2) Don't repeat relations
In the above example, we've connected each Track
to a Album
through a ForeignKey
. We don't need to do the opposite. That is, Album
does not need an explicit field to keep track of all of its Tracks
. You can do that when you query. The Django docs on making queries that span relationships are here.
This also has a further implication. You'll likely be connecting your Album
to an Artist
through a ForeignKey
. Because you can span relationships, you don't need to explicitly connect Tracks
and Artists
. Thus, a simple example of the three models should look like this:
from django.db import models
#Artist, Album, and Tracks are tables for music albums
class Artist(models.Model):
artist_name = models.CharField(max_length=100, null=False, blank=False)
short_bio = models.CharField(max_length=2000, null=False, blank=False)
added = models.DateTimeField(auto_now=True, auto_now_add=False)
updated = models.DateTimeField(auto_now=False, auto_now_add=True)
class Album(models.Model):
album_name = models.CharField(max_length=150, null=False, blank=False)
artist = models.ForeignKey(Artist)
active = models.BooleanField(default=True)
slug = models.SlugField(null=True, blank=True)
added = models.DateTimeField(auto_now=True, auto_now_add=False)
updated = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.album_name
class Track(models.Model):
track_name = models.CharField(max_length=200, null=False, blank=False)
album_name = models.ForeignKey(Album)
This is also subject to the caveat that if you'll be connecting an Album
to multiple Artists
, you'll need to tweak it somewhat. This would be like if you separated the band members out individually, i.e. "Abbey Road" is an Album
for four different Artists
: John, Paul, George, and Ringo.
3) Defining the model error
The problem you noted in (2) relating to models should go away once you stop repeating relations. Basically you can't use a model as a relation until you've already defined it. This was causing a problem as you were doing ManyToMany
on both models to each other. One of them has to come before the other, which will result in an import problem. You could also set null=True
if you wanted to use one before it was defined, but there's really no need in this case.
Let me know if any of this is unclear or if you have any further questions.
EDIT:
Additional tip:
If you're going to be using added
and modified
fields on many models, you might want to use the django-model-utils
package. Docs here. You can subclass a TimeStampedModel
that automatically makes created
and modified
fields. See here.
Thus:
from model_utils.models import TimeStampedModel
class Artist(TimeStampedModel):
artist_name = models.CharField(max_length=100, null=False, blank=False)
short_bio = models.CharField(max_length=2000, null=False, blank=False)