Synnipoe
Synnipoe

Reputation: 200

How to retrieve object that a different object is linked to in template? Django

I have a quiz model and a view where I'm displaying a list of all the quizzes on the page. I want to show the score that they got alongside each quiz. Currently, I have a score model that links to each quiz and the user that took the quiz. I want to do something like Score.objects.filter(user=request.user, quiz=quiz).get_percentage() to show the percentage achieved for that quiz. However this doesn't work in template code of course.

def learn(request): #Quiz Screen
    context = {
        'quizzes':Quiz.objects.all(),
        'scores':Score.objects.filter(user=request.user),
    }
    return render(request, 'quiz_app/learn.html', context)


{% extends "quiz_app/base.html" %}
{% block content %}
    <a href="{% url 'quiz-create' %}">New Quiz</a>
    {% for quiz in quizzes %}
        <a id="quiz-anchor" href="{% url 'quiz-detail' quiz.id %}">
            <article class="quiz-thumbnail-large">
                <h2>{{ quiz.title }}</h2>
                <h3>{{ quiz.question_amount }} Questions</h3>
                <p>Score: {{ quiz.score.get_percentage }}%</p>
            </article>
        </a>
    {% endfor %}
{% endblock content %}
class Quiz(models.Model):
    title = models.CharField(max_length=100) #or TextField
    #slug = models.SlugField(max_length=200, default=1) #url
    video_link = models.CharField(max_length=100, default="https://www.youtube.com/watch?v=p60rN9JEapg")
    question_amount = models.IntegerField()
    author = models.ForeignKey(User, default=1, on_delete=models.CASCADE, related_name='quiz_author',)
    date_created = models.DateTimeField(default=timezone.now)

    class Meta:
        verbose_name_plural = "Quizzes"

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('quiz-detail', kwargs={'pk': self.pk})


class Score(models.Model):
    quiz = models.ForeignKey(Quiz, default=1, on_delete=models.CASCADE)
    user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
    correct_answers = models.IntegerField()
    incorrect_answers = models.IntegerField()

    def __str__(self): #returns as a/b
        score = str(self.correct_answers) + '/' + str(self.get_total_answers())
        return score

    def add_correct_answers(self, amount):
        self.correct_answers = self.correct_answers + amount
        self.save()

    def add_incorrect_answers(self, amount):
        self.incorrect_answers = self.incorrect_answers + amount
        self.save()

    def get_total_answers(self):
        total = self.correct_answers + self.incorrect_answers
        return total

    def get_percentage(self):
        percentage = round(self.correct_answers / self.get_total_answers() * 100)
        return percentage

Upvotes: 0

Views: 141

Answers (1)

Pedram
Pedram

Reputation: 3920

So as you have a foreign Key relationship between Quiz and Score, you can have multiple scores for a single quiz, therefore you should use the backward relationship from the quiz model like this:

{% extends "quiz_app/base.html" %}
{% block content %}
    <a href="{% url 'quiz-create' %}">New Quiz</a>
    {% for quiz in quizzes %}
        <a id="quiz-anchor" href="{% url 'quiz-detail' quiz.id %}">
            <article class="quiz-thumbnail-large">
                <h2>{{ quiz.title }}</h2>
                <h3>{{ quiz.question_amount }} Questions</h3>
                {% for score in quiz.score_set.all %}
                    <p>Score: {{ score.get_percentage }}%</p>
                {% endfor %}
            </article>
        </a>
    {% endfor %}
{% endblock content %}

Edit

This is a quick fix:

{% extends "quiz_app/base.html" %}
{% block content %}
    <a href="{% url 'quiz-create' %}">New Quiz</a>
    {% for quiz in quizzes %}
        <a id="quiz-anchor" href="{% url 'quiz-detail' quiz.id %}">
            <article class="quiz-thumbnail-large">
                <h2>{{ quiz.title }}</h2>
                <h3>{{ quiz.question_amount }} Questions</h3>
                {% for score in quiz.score_set.all %}
                    {% if score.user == request.user %}
                        <p>Score: {{ score.get_percentage }}%</p>
                    {% endif %}
                {% endfor %}
            </article>
        </a>
    {% endfor %}
{% endblock content %}

But it's not a good idea, because you will retrieve all the score for all the users first, and then filter them; It's better to use a template tag here.

Upvotes: 2

Related Questions