tjb1982
tjb1982

Reputation: 2259

Django admin, many to many field, several duplicate entries

I have a situation where I'm trying to create a quick and easy admin interface for composers to list the instruments in a piece of music. What I am looking for is a single entity, an Instrumentation, which defines a particular combination of instruments. For example, a saxophone quartet might consist of:

  1. Soprano sax
  2. Alto sax
  3. Tenor sax
  4. Baritone sax

but it also might consist of two altos, tenor and bari instread. The problem gets worse when you try to add an entire section (like 1st violins--as many as 18 members).

The initial model I came up with looks like this:

class Work(Post):
    authors = models.ManyToManyField(Individual)
    title = models.CharField(max_length=255)
    subtitle = models.CharField(max_length=255, blank=True)
    program_notes = models.TextField(blank=True)
    notes = models.TextField(blank=True)
    media = models.ManyToManyField('Upload')

class Composition(Work):
    instrumentation = models.ForeignKey('Instrumentation')

class Instrumentation(models.Model):
    forces = models.ManyToManyField(Instrument)
    types = models.ManyToManyField('InstrumentationType')

class InstrumentationType(models.Model):
    type = models.CharField(max_length=255)
    variation = models.SmallIntegerField(default=0)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

I plan to later map each instrument in the piece to a performer in a rehearsal, concert, etc., so it's more than a simple count that I need. If I were doing this without django (i.e. just SQL and database design), I would have a mapping table with

Instrumentation :

It looks like Django is creating this exact situation for me in the database, but for some reason the framework needs type, composition_id and instrument_id to be unique together. The admin interface (multiselect box) also makes it clear that having multiple similar entries isn't how the many to many field was designed to work. So how do I achieve this? Is there an established workaround for this?

Upvotes: 0

Views: 2257

Answers (1)

tjb1982
tjb1982

Reputation: 2259

The chosen answer to this question solves it. I needed to explicitly define the mapping table and then use the admin inline feature to fix the interface.

models.py:

class Instrumentation(models.Model):
    forces = models.ManyToManyField(Instrument, through='InstrumentationForces')
    types = models.ManyToManyField('InstrumentationType')

class InstrumentationForces(models.Model):
    instrument = models.ForeignKey(Instrument)
    instrumentation = models.ForeignKey(Instrumentation)

admin.py:

class InstrumentInline(admin.TabularInline):
    model = InstrumentationForces
    extra = 3

class InstrumentationAdmin(admin.ModelAdmin):
    filter_horizontal = ('types',)
    inlines = (InstrumentInline,)
admin.site.register(Instrumentation, InstrumentationAdmin)

Upvotes: 2

Related Questions