Reputation: 309
I'm new at Django and have a few problems getting my mind around manytomany relatiosnhips and Manytoone (i.e Foreign key).
My setup is this.
I have class A, Class B, Class C
Every Class B object must belong to a Class A object. They cannot belong to more than one Class A object. A more practical example could be if Class A is a Music Band and class B is a song with that Band. Most Bands will have more than one song but every song must belong to a Band (in this example a song can never have multiple Bands).
Class C is a listing of individual Band members. So every band member can be associated with an arbitrary number of songs as well as an arbitrary number of Bands. In other words a member of Band X can also be a member of Band Y.
My question then would be
How would i use the ForeignKey and ManytoMany relationships in this context?
This example is contrived just to make my situation easier to understand and to help me explain my issue. I would like the admin to display for each Class C object what Class B objects or Class A objects that Class C belongs go. The same goes for Class B and Class A.
If you look at Class A objects you should be able to se a listing of all Class B objects that belong to that particular Class A object.
Any and all input appreciated.
Upvotes: 6
Views: 1578
Reputation: 1731
Here's how I'd set it up (in your models.py
)
class Member(models.Model):
name = models.CharField(max_length=100)
...
def __unicode__(self):
return self.name
class Band(models.Model):
name = models.CharField(max_length=100)
members = models.ManyToManyField(Member)
...
def __unicode__(self):
return self.name
class Song(models.Model):
name = models.CharField(max_length=100)
band = models.ForeignKey(Band)
...
def __unicode__(self):
return self.name
Set up like this:
member.band_set.all()
gives you all bands a member belongs toband.members.all()
gives you the members of a bandsong.band
gives you the band for that songband.song_set.all()
gives you all songs for a bandNote that the band_set
on member and the song_set
on band are "reverse" relationships. They aren't explicitly defined in the models, but Django sets them up for you transparently. You can customize these by using the related_name
parameter on the field definition. Example:
class Band(models.Model):
members = models.ManyToManyField(Member,related_name='bands')
would let you get all the bands for a member as follows:
member.bands.all()
The admin will automatically provide the following:
However, if you want to see songs for a band, you'll have to do a little admin customization.
In your admin.py
:
from django.contrib import admin
class SongInline(admin.StackedInline):
model = Song
extra = 1
class BandAdmin(admin.ModelAdmin):
inlines = [SongInline]
admin.site.register(Band,BandAdmin)
admin.site.register(Member)
admin.site.register(Song)
This will let you view the songs right from the admin page -- and edit or add them as well! By following this template you could show all bands for a member as well.
You can get a more detailed introduction to the admin customization at http://docs.djangoproject.com/en/dev/intro/tutorial02/
Upvotes: 11
Reputation: 599550
This is all fairly straightforward. I've used the descriptive names below, to make it easier to follow.
class Band(models.Model):
name = models.CharField(max_length=255)
class BandMember(models.Model):
name = models.CharField(max_length=255)
bands = models.ManyToManyField(Band)
class Song(models.Model):
name = models.CharField(max_length=255)
band = models.ForeignKey(Band)
# get a band
myband = Band.objects.get(name='myband')
# all songs from that band
print myband.song_set.all()
# all members of that band
print myband.bandmembers.all()
# get a specific band member
dave = BandMember.objects.get(name='Dave')
# what bands is Dave a member of?
print dave.bands.all()
# what songs has Dave sung? (slightly more complicated)
print Song.objects.get(band__bandmember=dave)
Upvotes: 3