Consiglieri
Consiglieri

Reputation: 309

Django Relationships

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

Answers (2)

Matthew Christensen
Matthew Christensen

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 to
  • band.members.all() gives you the members of a band
  • song.band gives you the band for that song
  • band.song_set.all() gives you all songs for a band

Note 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:

  • Show all members for a band in a multi-select list
  • Show the band for a song in a single select list

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

Daniel Roseman
Daniel Roseman

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

Related Questions