Need help with Django model design, ManyToManyField “through” an intermediate model and its implications for uniqueness

StackOverflow https://stackoverflow.com/questions/1762174

Question

I have the following Django models: -

class Company(models.Model):
    name = models.CharField(max_length=50)
    is_active = models.BooleanField(db_index=True)

class Phase(models.Model):
    company = models.ForeignKey(Company)
    name = models.CharField(max_length=50)
    is_active = models.BooleanField(db_index=True)

class Process(models.Model):
    company = models.ForeignKey(Company)
    name = models.CharField(max_length=50)    
    phases = models.ManyToManyField(Phase, through='ProcessPhase')
    is_active = models.BooleanField(db_index=True)

class ProcessPhase(models.Model):
    process = models.ForeignKey(Process)
    phase = models.ForeignKey(Phase)
    order = models.PositiveIntegerField(help_text="At what step of your process will this phase occur?", unique=True)

A "company" has its "processes" and "phases". A process (of a company) is comprised of one or more phases (of the company). Each phase associated with a process has an "order". The requirement is that: -

  1. in a particular process of a company, a phase can appear only once;
  2. also "phase A" and "phase B" in a process cannot have the same order.

So I need to know: -

a) how to specify some "unique"s in the model definition to fulfill the above requirements;

b) what uniqueness, if any, is automatically implied by a ManyToManyField?

Was it helpful?

Solution

In your case, since you say "A process (of a company) is comprised of one or more phases (of the company)", it seems like you should have a structure like:

Company <----* Process <----* Phase

Company has its Processes, Process has its Phases. It's not really a ManyToMany relation, it's OneToMany (Process has many Phases, but each Phase is connected to one Process).

If so, you should have

class Phase(models.Model):
    process = models.ForeignKey(Process, null=True) # based on your comment, if a Phase does not belong to a Process, leave it null.
    phase = models.ForeignKey(Phase)
    order = models.PositiveIntegerField(help_text="At what step of your process will this phase occur?")


    class Meta:
        unique_togather = ("process", "order")

The unique_together in Meta class is what you want, I think. It enforces both in admin and on database level the uniqueness of those 2 fields together.


edit:
(ForeignKey field can be null - see this)


based on your comment:

Don't use ManyToMany, as it auto-generates the "table-in-the-middle", while you need it specific for your needs. Instead, try defining the different model (together with your Company, Phase and Process):

class PhaseOrder(models.Model):
  process = models.ForeignKey(Process)
  phase = models.ForeignKey(Phase)
  order = models.PositiveIntegerField(help_text="At what step of your process will this phase occur?")
  class Meta:
    unique_together = (("process", "order"), ("process", "phase"))

OTHER TIPS

Shouldn't a Phase then allways belong to a Process? If that is so, you could say that the Process and order combination of a phase should be unique.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top