marczin
marczin

Reputation: 25

Django: Get all object and return it to view

I'm new in python and Django also I was searching for answer but can't find it :( I have 3 classes in my app. First one class in my app is Exam, Question, Answer.

models.py

class Egzam(models.Model):
    name = models.CharField(max_length=200, default='kolokwium ')
    date = models.DateField('date publish')
    code = models.CharField(max_length=200) 

    def __str__(self):
        return str("%s %s" % (self.date, self.name))

class Question(models.Model):
    egzam = models.ForeignKey(Egzam, on_delete=models.CASCADE)
    name = models.CharField(max_length=200) # nazwa pytania

    def __str__(self):
        return self.name

class Answer(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    answer_text = models.CharField(max_length=200) #treść odpowiedzi
    correct = models.BooleanField(default=False)

    def __str__(self):
        return self.answer_text

So Egzam class can handle few Question and Question class can handle few Answers. What I want to do is list all exam's on index page and after I clicked on one of them, my app should open new page where I see all Question and Answers to this specific Exam. And I don't know how to return all Question and Answer's from specific Exam to one html. Here is rest of my code.

urls.py

app_name = 'kolos'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.EgzamView.as_view(), name='view'),
]

views.py

class IndexView(generic.ListView):
    template_name = 'kolos/index.html'
    context_object_name = 'egzam_list'

    def get_queryset(self):
        return Egzam.objects.all()

class EgzamView(generic.DetailView):
    model = Egzam
    template_name = 'kolos/egzam.html'


    def get_queryset(self):
         return Answer.obects.filter()

Upvotes: 2

Views: 2461

Answers (2)

ruddra
ruddra

Reputation: 52028

You can try like this:

in template kolos/egzam.html

{% for question in object.question_set.all %}
     {{ question.name }}
     {% for answer in question.answer_set.all %}
         {{ answer.answer_text }}
         {{ answer.correct }}
     {% endfor %}
{% endfor %}

And remove get_queryset method from EgzamView.

Please see the Many to one query section regarding how reverse query works(with _set).

Upvotes: 2

Aleksandar Stojadinovic
Aleksandar Stojadinovic

Reputation: 5049

Although there is nothing wrong with ruddra's answer I would suggest a similar approach. I would set the related_name on the foreign key relations. I find it useful and cleaner if I plan to often access bidiractional relationships. Like this:

class Question(models.Model):
egzam = models.ForeignKey(Egzam, on_delete=models.CASCADE, related_name='questions')
name = models.CharField(max_length=200) # nazwa pytania

def __str__(self):
    return self.name

class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='answers')
answer_text = models.CharField(max_length=200) #treść odpowiedzi
correct = models.BooleanField(default=False)

This way you can access the questions using the Egzam like this:

{% for question in object.questions.all %}
    {{ question.name }}
    {% for answer in question.answers.all %}
        {{ answer.answer_text }}
        {{ answer.correct }}
    {% endfor %}
{% endfor %}

Also, not going into to much reasons, currently it is preferable to use .format() instead of % for strings. Like this

def __str__(self):
    return str("{} {}".format(self.date, self.name))

Upvotes: 1

Related Questions