9minday 9minday - 1 year ago 53
Python Question

related classes of related classes django 1.9

I am building a site that display guides.
Each guide has steps.
Each step has sub_steps.

I have done it with PK like this code.

How do I return for example sub_step 3 of step 5 in guide 2?

Also I have tried to do the inline admin function to add steps inside the guide and sub_steps inside the steps to keep it organised but can only get it to work with step in guide. How is this done?

class Guide(models.Model):
name = models.CharField(max_length=200)
guide_category = models.CharField(max_length=70)
guide_why = models.TextField()
guide_how = models.TextField()

def __unicode__(self):
return self.name

class Step(models.Model):
guide = models.ForeignKey(Guide, on_delete=models.CASCADE)
sequence_number = models.PositiveIntegerField(default=1)
step_title = models.CharField(max_length=10)

class Meta:
unique_together = ("guide", "sequence_number")

def __unicode__(self):
return self.step_title

class Task(models.Model):
step = models.ForeignKey(Step, on_delete=models.CASCADE)
sequence_number = models.PositiveIntegerField(default=1)
task_title = models.CharField(max_length=10)
task_img = models.ImageField()
task_task = models.TextField()
task_description = models.TextField()

class Meta:
unique_together = ("step", "sequence_number")

def __unicode__(self):
return self.task_title

Answer Source

Regarding of your first question: if you want to retrieve the steps and substeps by its sequence number, you cannot rely on the PK of each model, since the PK does not follow a sequence related to the parent table.

try this:

class Step(models.Model):
    guide = models.ForeignKey(Guide, on_delete=models.CASCADE)
    sequence_number = models.PositiveIntegerField()
    step_title = models.IntegerField(default=1)

    class Meta:
        unique_together = ("guide", "sequence_number")


class Sub_step(models.Model):
    step = models.ForeignKey(Step, on_delete=models.CASCADE)
    sequence_number = models.PositiveIntegerField()
    sub_step_title = models.IntegerField(default=1)
    sub_step_img = models.ImageField()
    sub_step_task = models.TextField()
    sub_step_description = models.TextField()

    class Meta:
        unique_together = ("step", "sequence_number")

unique_together will create a constraint in the database to ensure that there is a unique sequence_number for every parent object.

You need to set the sequence_number when the models are inserted in the database.

Then, you can do something like:

guide = Guide.objects.get(...)  # fetch by PK maybe
step_5 = Step.objects.get(guide=guide, sequence_number=5)
example = Sub_step.objects.get(step=step_5, sequence_number=3)

Hope this helps.

EDIT >>

You need to consider these points:

  • You can't set default=1 to the sequence number; it must be unique for every parent model. You will need to manually update the sequence number or create a migration for that.
  • As pointed by @Selecsosi, the unique_together constraints won't be applied. The names must refer to properties within the model.
  • If you are managing your database through migrations (which you should), you may need to do this change in more than one step:
    1. add the sequence_number to the models, set the null=True property. Don't set the unique_together property in the Meta class.
    2. make and apply the migration
    3. create a migration to update the sequence_number of each model accordingly (check here on how to create a custom migration).
    4. apply the migration, check that there are no duplicates on parent_model, sequence_number in the database
    5. set the unique_together property in the Meta class, remove the null=True property of the sequence numbers
    6. create and apply the migration
    7. take care of the sequence_number every time you insert new steps and substeps

<< EDIT

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download