a list inside a list - django views - django

{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
and I have
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = RequestContext(request, {
'latest_question_list': latest_question_list,
})
return HttpResponse(template.render(context))
But how do I do an inner list?
Since its a list of lists how do I define the lists in such a way that they can be access correctly? The question model certainly doesn't contain any list of comments. I can do a query but I really have no idea where to begin here.
Thanks for any suggestion.
edit:
have a list of questions from the database. The code above lets me view them just fine. But every list has multiple comments. How do I list all the comments per question? I need another for loop in the html but I am not sure how to give each question its own data in the view.

This isn't at all a question about lists.
Presumably you have a separate Comment model, and that model has a ForeignKey to the Question model; if you don't have that structure, then you should.
Then it's simply a matter of following the reverse relationship for each question:
{% for question in latest_question_list %}
...
{% for comment in question.comment_set.all %}
{{ comment.text }}
{% endfor %}
{% endfor %}
Note that this exact structure is well described in the tutorial, with the example of Poll and Choice.

Related

Using jinja variable as dictionary key

I'm making a django app to do with tests/exams. Two of the models in this app are the "Question" and "Answer" model which have a one-to-many relationship. On the page, each question will be listed with all of its possible answers below it which the user can choose from.
In my views.py file, after getting the list of question objects, the best way I thought of for storing the answers was in a dictionary like so:
answers = {}
for question in questions:
answers[question.id] = Answer.objects.filter(question=question.id)
Then, for the template, I thought I would be able to do something like:
{% for question in questions %}
<h2>{{ question.title }}</h2>
<ul>
{% for answer in answers.{{ question.id }} %}
<li>{{ answer.title }}</li>
{% endfor %}
</ul>
{% endfor %}
The error arises in this line - {% for answer in answers.{{ question.id }} %}.
I've tried rewriting this line as per this post which suggested things like:
{% for answer in answers[question.id] %}
and
{% for answer in answers.get(question.id) %}
but none of these worked.
Please let me know if there is a syntax in Jinja that allows this or else if there is a better way of me passing the answers variable in my views.py file altogether.
You can use the _set.all() convention to get all the related items:
{% for answer in question.answer_set.all %}
{{ answer.id }}
{% endfor %}
This works, but if you want to have a more readable version you can define a related_name in your model:
class Question(models.Model):
prompt = (models.CharField)
class Answer(models.Model):
question = models.ForeignKey(Question, related_name="answers")
correct = models.BooleanField()
prompt = models.CharField()
And then you can use that related name instead of the _set:
{% for answer in question.answers.all %}
{{ answer.id }}
{% endfor %}
which makes it a bit more readable.

django template falling into unexpected logic

I have a view that is supposed to be gathering all the objects for a currently authenticated user from three tables TSFH, TSUH, and TSJH and gather all those objects for the currently logged in user, if that user exists.
However, my view logic is currently falling into the else statement it appears.
Can someone help me debug why this might be happening?
My tables have data for the currently logged in user, so I am not sure why this is happening.
Views.py
def SHO(request):
TSUH = TSUH.objects.filter(FKToUser_id=request.user).all()
TSFH = TSFH.objects.filter(FKToUser_id=request.user).all()
TSJH = TSJH.objects.filter(FKToUser_id=request.user).all()
return render(request, 'page.html', {
'TSUH':HasTSUH,
'TSFH':HasTSFH,
'TSJH':HasTSJH
})
templates/page.html
{% autoescape on %}
{% if HasTSUH %}
{% for t in HasTSUH %}
<li>{{ t.begin }}<span></li>
{% endfor %}
{% elif HasTSFH %}
{{ HasTSFH }}
{% elif TSJH %}
{{ TSJH }}
{% else %}
It appears you haven't done anything yet.
{% endif %}
However it keeps displaying:
It appears you haven't done anything yet.
what am i doing wrong here? thanks
The names in the template are the keys of the context dict. You've used TSUH, TSFH, and TSJH, without the Has.

NoReverseMatch when rendering page

I seem to know where the issue is located since I can get around it, but for getting around it I have to sacrifice a function I really want to keep.
Here is the relevant code in the non-working state:
{% if sections %}
{% for item in sections %}
<a class="sections" href="{% url 'sections:generate' item.section.slug %}">{{ item.section.title }}</a>
{% for subsection in item.subsections %}
<p>{{ subsection.title }}</p>
{% endfor %}
{% endfor %}
{% else %}
<p>Error retrieving sections or no sections found</p>
{% endif %}
The problem part above is in the link tag. Let me explain by showing the related view.py:
def index(request):
sections = Section.objects.all()
context = {
'sections': [],
}
for section in sections:
context.get("sections").append(
{
'section': section,
'subsections': get_subsections(section),
}
)
return render(request=request, template_name='index.html', context=context)
So, 'sections' is an iterable list of items, containing for every items a dictionary with two entries. One, 'section' and one 'subsection'. There are multiple subsections for every section, this is what I really want to accomplish.
Ordinarily, when not bothering with subsections and simply iterating over a list of sections works fine. The template code for that would look something like:
{% for section in sections %}
{{ section.title }}
{% endfor %}
NOTE! The code above works just fine! But as soon as I add 'sections' as a list of dictionaries and have to reference the slug by item.section.slug the pages stop rendering.
Please advise.
Try using tuples:
View:
context['sections'] = [(section, tuple(get_subsections(section))) for section in sections]
Template:
{% for section, subsections in sections %}
<a class="sections" href="{% url 'sections:generate' section.slug %}">{{ section.title }}</a>
{% for subsection in subsections %}
<p>{{ subsection.title }}</p>
{% endfor %}
{% endfor %}

Determine order of iteration in django template for loop

I am populating a list in my view:
hits_object = {}
hits_object['Studio'] = hitlist('Studio',days)
hits_object['Film'] = hitlist('Film',days)
hits_object['Actor'] = hitlist('Actor',days)
hits_object['Historical Event'] = hitlist('Event',days)
hits_object['Pop Culture'] = hitlist('Pop_Culture',days)
Then I am displaying it in my template:
{% for model, hits in hits_object.items %}
{% if hits %}
<u> Most {{ model }} views in last {{ days }} days</u>
<ol>
{% for hit in hits %}
<li>{{ hit.name }} - {{ hit.count }}</li>
{% endfor %}
</ol>
</u>
{% endif %}
{% endfor %}
The problem is that the models display in a seemingly random order: first Actor, then Studio, Historical Event, Film, etc.
How can I force the for loop in the template to iterate the object in a specific order?
Dictionaries are unordered. If you need to preserve insertion order, use an ordered dict implementation - there's one in django.utils.datastructures.SortedDict, for example.
Or, since you don't seem to be using the key of the dictionary but are just iterating through, appending to a simple list would seem to be easier.
As Daniel explained, dictionaries are accessed randomly. Here is one way to do what you want:
hits_object = list()
hits_objects.append(
(hitlist('Studio',days),
hitlist('Film',days),
hitlist('Actor',days),
hitlist('Event',days),
hitlist('Pop_Culture',days))
In your view:
{% for studio,film,actor,event,pop_culture in hits_objects %}
# do something...
{% endfor %}

How to limit a collection of objects related on a foreign key in Django Templates?

Given is a model called "comment" with a foreign key relationship to a model called "task".
{% for task in tasks %}
{% for comment in task.comment_set.all %}
{{ comment }}
{% endfor %}
...
What is the best way to limit this to 5 comments like:
Entry.objects.all()[:5]
{% for task in tasks %}
{% for comment in task.comment_set.all|slice:"5" %}
{{ comment }}
{% endfor %}
{% endfor %}
You don't. You should not do "real work" in a template, this breaks the MVC pattern.
Do the real work in the view, and pass the data to the template (using the context dictionary).
def handle_comments(request):
tasks = Task.objects.all()
comments = {}
for task in tasks:
comments[task] = task.comment_set.all()[:5]
return render_to_response('commenting.html', {'comments': comments})
You can then iterate over the comments in your template:
{% for task, task_comments in comments.items %}{{ task }}{% endfor %}