Erik D.
Erik D.

Reputation: 27

Is it possible to enumerate identical instances of a model?

I'm trying to create a set of models for keeping track of the signal flow in audio equipment. In order to properly model a mixer, for instance, I'd need to keep track of several identical inputs and outputs. For instance:

class signal(models.Model):
    # e.g., 1/4" mono cable
    name = models.CharField(max_Length=100)
    def __unicode__(self):
        return self.name

class component_type(models.Model):
    # e.g., mixer
    name = models.CharField(max_length=250)
    def __unicode__(self):
        return self.name

class input(models.Model):
    # e.g., a single channel on a mixer
    type = models.ForeignKey("signal")
    component_type = models.ForeignKey("component_type")
    def __unicode__(self):
        return "%s - %s" % (self.component_type.name, self.type.name)

I can add a number of separate instances of a 1/4" mono jack for a mixer; that's no problem. What I'd like to do is auto-enumerate them, so that I can keep track of each individual channel. For instance, I'd like to have the first instance of a 1/4" mono input on a mixer to be represented as 'Mixer - 1/4" Mono 1' and the second instance to be 'Mixer - 1/4" 2', rather than having them both named 'Mixer - 1/4" Mono.'

I imagine this will require an additional field and hijacking the save method, but I'm not quite sure of how to go about it. Thanks!!

Upvotes: 0

Views: 78

Answers (1)

ppetrid
ppetrid

Reputation: 3845

Something like this could be a good place to start:

from django.db.models import F

class Input(models.Model):
  type = models.ForeignKey("signal")
  component_type = models.ForeignKey("component_type")
  number = models.IntegerField(default=0)

  def save(self, *args, **kwargs):
    if not self.pk:
      self.number = Input.objects.filter(component_type_id=self.component_type_id, type=self.type_id).count() + 1
    super(Input, self).save(*args, **kwargs)

  def delete(self, *args, **kwargs):
    Input.objects.filter(component_type_id=self.component_type_id, type=self.type_id, number__gt=self.number).update(number=F('number')-1)
    super(Input, self).delete(*args, **kwargs)

  def __unicode__(self):
        return "%s - %s" % (self.component_type, self.type, self.number)

We override the delete method to ensure that when an input gets deleted, all inputs with a higher number get a new correct number.

Some notes:

1) Please don't shoot if this doesn't work as is, the code is a sketch

2) I took the liberty of capitalizing model names, it's a standard practice which you could also adopt

3) In the delete method I use the update method to update the appropriate inputs at once without generating db overhead (one query). If this doesn't work exactly as is, you should still work on that direction

4) The presented unicode method does not explicitly use the component_type.name and type.name properties, but calls the corresponding unicode methods of each model (you might change the ComponentType's unicode in the future and Input will display the new version)

Upvotes: 1

Related Questions