Home > Enterprise >  Why does my Django query from Postgres database return the query set in reverse order
Why does my Django query from Postgres database return the query set in reverse order

Time:02-27

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 >
              <!-- 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
            }

CodePudding user response:

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.

  • Related