简体   繁体   中英

How to order nested model in django DetailView

I'm using Django 1.10

I'm learning Django by make Survey program

I made three models, Survey include Questions, and Question include Choices

Models.py

from django.db import models

class Survey(models.Model):
    title = models.CharField(max_length = 200)
    description = models.TextField()
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.title

class Question(models.Model):
    survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
    question_text = models.CharField(max_length=200)

    def __str__(self):
        return "%s : %s" % (self.survey, self.question_text)

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return "%s - %s" % (self.question, self.choice_text)

I want to show my result page ordered by votes but now, I just show non-ordered result page.

I think I have to modify my views.py using queryset or extra context. but I don't know how to use.

Here is my views and template.

views.py

class SurveyResultsView(DetailView):
    model = Survey
    template_name = 'survey/results.html'

results.html

{% extends 'survey/base.html' %}
{% block content %}

<div class="survey-info-container">
  <h1>Results of {{survey.title}}</h1>
  <p>{{survey.description}}</p>
  <p>{{survey.pub_date}}</p>
</div>

<div class="result-container">
  {% for question in survey.question_set.all %}
  <p>
    <h3>{{question.question_text}}</h3>
    <ul>
        {% for choice in question.choice_set.all %}
          <li>{{choice.choice_text}} -- {{choice.votes}} votes </li>
        {% endfor %}
    </ul> 
  </p>
  {% endfor %}
</div>
{% endblock content %}

Thanks for read.

I can come up with three different ways that you can achieve this.

Sort in Template

The first, most obvious one is to sort the choice objects when you fetch them inside your template. You do this using the dictsort filter ( Docs ) that you apply like I show here below.

{% for choice in question.choice_set.all|dictsort:"votes" %}
    <li>{{choice.choice_text}} -- {{choice.votes}} votes </li>
{% endfor %}

Note, there is also a dictsortreversed ( Docs ) filter that order the objects in reversed order.

Function on Model

Another way of doing it is defining a function on the Question model that returns the entries in the sorted order that you wish for, and then instead of calling question.choice_set.all() in your template you would call the function instead.

Example:

class Question(models.Model):
    #... 
    def choice_set_sorted(self):
        # Can set .order_by('-votes') to reverse order
        return self.choice_set.all().order_by('votes')

Template:

{% for choice in question.choice_set_sorted %}
    <li>{{choice.choice_text}} -- {{choice.votes}} votes </li>
{% endfor %}

Setting the Meta class

The third option is to set a default ordering on your Model. If you always want your Choice to be ordered by votes this could be a good idea.

You do this by setting the Meta class in your model with the ordering property set to the field that you want to order by ( Docs ).

So the way you would implement this would be:

class Choice(models.Model):
    #...
    class Meta:
        ordering = ['votes']

////

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM