Search code examples
djangomany-to-many

Django many-to-many relationship with extra fields


I am building a simple interface to a biological database using the django-admin to populate the db. I want tot to use a many-to-many relationship for a questionnaire to fish species (one questionnaire can have more than one species and one species can be present in more than one questionnaire). The two models in question:

class Species(models.Model):
    fish_spp_name = models.CharField(max_length=255, unique=True)


class Questionaire(models.Model):
    # ...
    fish_caught = models.ManyToManyField(Species)

now, I want to my data to contain a number of each species caught, per questionnaire. So, for example, I can associate 3 different species with questionnaire id=1, but how do I include that, say 2 of the first species, 1 of the second and 4 of the third were caught?


Solution

  • Define another models Caught to hold the information per catch. Give it a related_name to make it easier to refer to in your code. You might also want to unique_together appropriate fields.

    class Species(models.Model):
        name = models.CharField(max_length=255, unique=True)
    
        def __unicode__(self):
            return '%s/%d' % self.name
    
    class Questionaire(models.Model):
        pass
    
    class Caught(models.Model):
        species = models.ForeignKey(Species)
        number = models.IntegerField()
        questionaire = models.ForeignKey(
            Questionaire, related_name='catches')
    
        def __unicode__(self):
            return '%s/%d' % (self.species.name, self.number)
    

    Use it like this:

    (InteractiveConsole)
    >>> from app.models import *
    >>> s1 = Species(name='Salmon')
    >>> s1.save()
    >>> s2 = Species(name='Mackerel')
    >>> s2.save()
    >>> q = Questionaire()
    >>> q.save()
    >>> c1 = Caught(species=s1, number=7, questionaire=q)
    >>> c2 = Caught(species=s2, number=5, questionaire=q)
    >>> c1.save()
    >>> c2.save()
    >>> q.catches.all()
    [<Caught: Salmon/7>, <Caught: Mackerel/5>]
    >>>