1

I have a model called "Step" that is connected to a learning guide through a foreign key. In my views.py file I am simply querying the steps using this learning_guides_steps = learning_guide.step_set.all() and in the templates I am just looping through the steps using a for loop and displaying the title of the steps like this

        {%for step in learning_guides_steps%}
            <div class="entire_step">
              <!-- Displaying the title of the step with an angle down button beside the title -->
                <div class = "btn-group step" >
                   <a href = "#" class = "btn stepname" role = "button" style = "font-size: 18px;"> {{forloop.counter}}. {{step.title}}</a>
                </div>
            </div>

However when I display it in website its printing in reversed order. Can anyone explain why this is happening and how I can fix this? I am new to Django and Postgres, so any help would be appreciate it. Thank you. My Step model and the views is given below


      class Step(models.Model):
         title = models.CharField(max_length=200, null=False)
         step_description = models.TextField(max_length=1000, null=False)
         # enforces one-to-many relationship between LearningGuide and Step. 
         # Deleting a LearningGuide deletes all the associated steps (CASCADE delete)
         learning_guide = models.ForeignKey(LearningGuide, on_delete=models.CASCADE)
        

class LearningGuide(models.Model):
    title = models.CharField(null=False, max_length=50)
    image = models.ImageField(upload_to='learning_guides_images/')
    short_description = models.TextField(max_length=100, null=False)

    category = models.ForeignKey(Category, on_delete=models.DO_NOTHING)

    indicators = models.ManyToManyField(Indicator, blank=True)

    external_resource = models.BooleanField(default=False, blank=True)
    external_resource_link = models.URLField(null=True, blank=True)


My views.py file:


            learning_guide = LearningGuide.objects.get(pk=learning_guide_id)
            learning_guides_indicators = learning_guide.indicators.all()
            indicators = Indicator.objects.all()

            learning_guides_steps = learning_guide.step_set.all()
            context = {
                'learning_guide': learning_guide,
                'indicators': indicators,
                'learning_guides_indicators':learning_guides_indicators,
                'learning_guides_steps':learning_guides_steps,
                'homepage':False
            }
2
  • Querysets in Django are not ordered, by default, but there are two ways you can order them. You can add order_by to your query, or you can set the order in the model itself. I'd need to see your learning guide model to be more specific. Commented Feb 26, 2022 at 23:00
  • I have updated the question and it includes the learning guide model. Also, is there any way for me to use order by inside the Django template tags? Thank you for taking the time to answer the question. :) Commented Feb 27, 2022 at 0:48

1 Answer 1

2

Option 1 (probably the easiest)
Order the queryresults in your view by using order_by:

learning_guides_steps = learning_guide.step_set.all().order_by('step__title')
# OR to order in the opposite direction,
learning_guides_steps = learning_guide.step_set.all().order_by('-step__title')

Note that I'm guessing you want to order by the title of the step, but you can order by any other field by just replacing title in the order_by, like order_by('step__pk') if you want to order by the step's primary key. Note that the - in each case reverses the direction. And note the double underscore between step and title step__title because you are ordering by a ForeignKey.

Option 2 Set the default ordering on the model itself by using the class Meta:

class Step(models.Model):
    title = models.CharField(max_length=200, null=False)
    step_description = models.TextField(max_length=1000, null=False)
    learning_guide = models.ForeignKey(LearningGuide, on_delete=models.CASCADE)

    class Meta:
        ordering = ['title']
        # OR in the other direction
        ordering = ['-title']

This will require you to run python manage.py makemigrations and python manage.py migrate

Option 3
Add an order field to the step, and order by that. This way you can set the order, and not order alphabetically, or by an auto generated primary key:

class Step(models.Model):
    title = models.CharField(max_length=200, null=False)
    order = models.PositiveIntegerField(default=1)
    step_description = models.TextField(max_length=1000, null=False)
    learning_guide = models.ForeignKey(LearningGuide, on_delete=models.CASCADE)

    class Meta:
        ordering = ['order']
        ordering = ['-order']

Note that this third option will also require you to run python manage.py makemigrations and python manage.py migrate. I've added the default value of 1 to the order so that this migration will not complain about a NULL value, but it means that ALL the Steps will have an order of 1 until you change it. There is a way around this, but I think this will work.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer. I can't upvote because I don't have enough reputation points to do so :'(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.