Render multiple quersets in html page in Django - python

views.py
def f_page(request, slug, f_slug):
f = get_object_or_404(F, slug= f_slug)
if f:
events = f.event_set.order_by('-pub_date')
if events:
for event in events:
comments = event.comment_set.order_by('-pub_date')
variables = RequestContext(request, {
'f' : f,
'events' : events,
'comments' : comments,
})
return render_to_response('f_page.html', variables)
Here events and comments are iterables. Each f has multiple events and then each event has multiple comments. The problem is how do I render this in my html page.I have tried this but it didn't work:
{% for event in events %}
{{ event.author.first_name }}
{{ event.pub_date }}
{{ event.description }}
{% for comment in comments %}
{{ comment }}
{{ comment.author.first_name }}
{% endfor %}
{% endfor %}
The events part shows up right but the comment set doesn't show up.
My models work just fine I have tried everything in the admin panel. I can see where I'm messing it up but am unable to solve it. In 'views.py' the comments object for each event is not being saved. But, I don't know how to resolve it.
Please help. Thanks in advance.

Instead of passing comments to template you can get it in template.
{% for event in events %}
{{ event.author.first_name }}
{{ event.pub_date }}
{{ event.description }}
{% for comment in event.comment_set.all %}
{{ comment }}
{{ comment.author.first_name }}
{% endfor %}
{% endfor %}
Add ordering field in your models Meta class so that event.comment_set.all gives you data in your order.
class Comment(Model):
...
class Meta:
ordering = ['-pub_date']

Related

Trying to understand Django's communication between view and template

(edited)
I come from a web2py background and find Django a much more complicated framework to learn and use than web2py.
After the first answer, I have adapted the description of my problem.
In my view I have:
def team(request):
hr = dict(name="Some Name", photo="/static/images/HR.jpg", url="http://some.website.com/?page_id=3602")
js = dict(name="Some Name2", photo="/static/images/JS.jpg", url="http://some.website.com/?page_id=3608")
context = {team:[hr,js]}
return render(request, "wos_2017_2/team.html", context)
In the template I have
<ul>
{% for person in context.team %}
<li> {{ person.name }} {{ person.photo }} {{ person.url }} </li>
{% endfor %}
</ul>
There is absolutely no output.
This works in normal python:
hr = dict(name="Some Name", photo="/static/images/HR.jpg", url="http://some.website.com/?page_id=3602")
js = dict(name="Some Name2", photo="/static/images/JS.jpg", url="http://some.website.com/?page_id=3608")
context = dict(team = [hr,js])
for i in context['team']:
print(i['name'], i['photo'], i['url'])
With output
Some Name /static/images/HR.jpg http://some.website.com/?page_id=3602
Some Name2 /static/images/JS.jpg http://some.website.com/?page_id=3608
Why am I not getting any result in Django?
Your first example is correct. Sadly you have a small typo in your first line of code:
hr = dict(name="Some Name, ...),
The line ends with a comma ,. Now hr is becomes a tuple with a single element: the dict. Without the comma this works:
{{ team.0.name }}
{{ team.1.name }}
With your updated answer you need to change context.team to team in your template:
{% for person in team %}
The context dictionary is 'unpacked' in the template.
I was not able to comment so I had to post an answer.
Only immutable data types can be used as keys, i.e. no lists or dictionaries can be used If you use a mutable data type as a key, you get an error message.Tuple as keys are okay.
With what i can tell is the problem is in your view code:
This
context = {team:[hr,js]}
should be this:
context = {"team":[hr,js]}
or
context = dict(team=[hr,js])
<ul>
{% for person in team %}
<li> {{ person.name }} {{ person.photo }} {{ person.url }} </li>
{% endfor %}
</ul>
Was the correct way to read the dictionary in the template.

How To Avoid Logic In Template?

I'm trying to develop a forum application.
I'm trying to display the latest topic that's been posted in each category on a listing page. However, I realised after adding more than one category that I need a separate query for each single category or it just shows the newest topic overall.
I'm just not sure how to keep my logic in the view for the queries. Obviously, I could just perform the query inside of my for loop but that doesn't seem very MVT oriented.
Here's my views.py:
from django.shortcuts import render
from .models import ForumReply, ForumCategory, ForumTopic
def index(req):
categories = ForumCategory.objects.all()
#find latest topic or topic by reply
topic = ForumTopic.objects.latest('created_at')
reply = ForumReply.objects.latest('created_at')
if (topic.created_at > reply.created_at):
latest = topic
else:
latest = reply.topic
return render(req, "forum/category_listing.html",
{'categories': categories, 'latest': latest})
And my category_listing.html:
{% extends '__base.html' %}
{% block content %}
{% for category in categories %}
<div class="forum_category">
<h1>{{ category.title }}</h1>
{{ category.body }}
<br />
<em>Latest Post: </em> {{ latest.title }} by {{ latest.user }} at {{ latest.created_at|date:"D d F Y h:i" }}
</div>
<br />
{% endfor %}
{% endblock %}
You can create a custom template tag that returns the latest post for each category.
Something like this:
# views.py
def index(req):
categories = ForumCategory.objects.all()
return render(req, "forum/category_listing.html", {'categories': categories})
# templatetags/category_tags.py
#register.assignment_tag
def get_latest_post(category):
# perform logic here for selecting latest post for specific category
return latest
# category_listing.html
{% load category_tags %}
{% for category in categories %}
{% get_latest_post category as latest %}
<em>Latest Post: </em> {{ latest.title }} by {{ latest.user }} at {{ latest.created_at|date:"D d F Y h:i" }}
{% endfor %}
You can read the documentation for more information https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/#assignment-tags

Pass and View Dictionary from view to template in django

I am passing the dictionary to the view but it is now showing on the page.
i also have print the dictionary on the before passing, and it prints the whole dictionary on the screen perfectly. but when i pass it to the html page, it does not show at all..
view.py
def show_log_messages(request):
context = RequestContext(request)
log_dictionary = {}
count = 0
e = log_messages.objects.filter(log_status='Queue').values('sent_to', 'unique_arguments')
count = 0
logs = {}
for d in e:
count +=1
new_dict = {'email': d["sent_to"], 'log_id': d["unique_arguments"]}
logs[count] = new_dict
for keys in logs:
print logs[keys]['log_id']
print logs[keys]['email']
return render_to_response('show_logs.html', logs, context)
show_logs.html
{% if logs %}
<ul>
{% for log in logs: %}
{% for keys in log %}
<li>{{ log[keys]['email'] }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no logs present.</strong>
{% endif %}
it only show the heading not the list element.
Your code is very unpythonic and undjango. You should pass to template a list instead of dictionary.
Also shortcuts.render is much simpler to use than render_to_response.
def show_log_messages(request):
messages = log_messages.objects.filter(log_status='Queue') \
.values('sent_to', 'unique_arguments')
logs = [{'email': msg['sent_to'], 'log_id': msg['unique_arguments']}
for msg in messages]
return render(request, 'show_logs.html', {'logs': logs})
Template:
{% if logs %}
<ul>
{% for log in logs %}
<li>{{ log.email }} - {{ log.log_id }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no logs present.</strong>
{% endif %}
BTW, logs list is unnecessary here. You can pass messages queryset directly into template and show {{ log.sent_to }} and {{ log.unique_arguments }} in the <li> tag.
The render_to_response shortcut takes a dictionary. If you want to access logs in the template, it should be in that dictionary:
return render_to_response("show_logs.html", {'logs': logs}, context)
The second problem is that your django template is invalid. It looks like you're trying to write Python in the template. You'd probably find it helpful to read through the Django template language docs.
It's not clear to me what you're trying to display, so here's an example of looping through each log, and displaying its id and email. You should be able to adjust this to get the result you want.
{% if logs %}
{% for key, value in logs.items %}
{{ key }}, {{ key.log_id}}, {{ key.email }}
{% endf
{% else %}
<strong>There are no logs present.</strong>
{% endif %}

grouping fields in django form

I want to render form grouping fields. Form actually is created dynamically according to incoming dictionary
for f in settings.FORM_BIG_FIELDS:
self.fields[f['id']] = eval(f['type'])(label=f['label'], required=f.get('required', True))
self.fields[f['id']].groupp = f.get('group', 1)
groupp attribute means appropriate group, then I try to render it like
{% regroup form.fields.values by groupp as field_group %}
{% for group in field_group %}
<div class="group_{{ group.grouper }}">
{% for field in group.list %}
<p>
{{ field.all }}
{{ field }}
</p>
{% endfor %}
</div>
{% endfor %}
But as output I get the following
<django.forms.fields.CharField object at 0xb527388c>
<django.forms.fields.IntegerField object at 0xb52738ec>
<django.forms.fields.ChoiceField object at 0xb527394c>
I have read that these are not the same as BoundField object. How to render fields or is there any other better approaches to group fields?
If you do not want use any additional libraries, then the most easy solution is to render them manually, i would say. Otherwise you will just spend alot of time repeating the functionality of the library i copied as comment to your post.
There is always the case that things should be DRY. But we build websites for the users and user cares little about how the form rendering in template is done. For this reason we have often created form templates manually like this:
<div class="something">
{{ form.fieldname.label_tag }}{{ form.fieldname }}
</div>
Easyest way to organise it saving you some time. And in my opinion it is not that bad either, since this is not very common when you need fields organised by fieldsets.
I know this question is rather old, but I am sure there are still people who can benefit from a simple solution:
Say you have a group name and list of members. You can define a self.fieldset in your form's init to be a dictionary of {'group_1': ['member_1', 'member_2', ... ], ... }. Once you attach this to the form, you can pass it to views and from there to the template:
In forms.py:
class MyForm:
def __init__(self, current_user, *args, **kwargs):
super(YourForm, self).__init__(*args, **kwargs)
self.field['group'].queryset = Group.objects.filter(user = current_user)
...
In views.py:
form = self.Form(current_user)
the_fieldsets = form.fieldset
c = {'form': search_form,
'fieldsets': the_fieldsets }
In your template:
{% for field in form %}
<tr>
<td>{{field.label_tag}}</td>
{% if field.name == 'group' %}
<td>
<select id='{{field.id}}' name='{{field.name}}'>
{% for k,v in fieldsets.items %}
<optgroup label = {{k.name}}>
{% for val in v %}
<option name='{{val}} value = {{val.id}}> {{val.name}} </option> # Note that the select needs to return 'id', so value has to be {{val.id}}
{% endfor %}
</optgroup>
{% endfor %}
</select>
</td>
{% else %}
<td>{{field}}</td>
{% endif %}
<td>{{field.help_text}}</td>
<td>{{field.errors}}</td>
</tr>
{% endfor %}

flask and wtf - how can I direct tag attributes for fields?

After fiddling with wtforms, fields use widgets to actually render them to html. I wrote some custom field/widget to draw html in a way that I'd more like to. But here's a question:
suppose I want to render them with pre-defined css class or give actual details myself.
How can I achieve this? and on what phase of handling requests(at Form class declaration? or when setting attributes to give Form some Fields? or when I'm actually calling them in jinja2 templates) I should do that?
I use a Jinja macro something like this:
{% macro field_with_errors(field) %}
{% set css_class=kwargs.pop('class', '') %}
{% if field.type in ('DateField', 'DateTimeField') %}
{{ field(class='date ' + css_class, **kwargs) }}
{% elif field.type == 'IntegerField' %}
{{ field(class='number ' + css_class, **kwargs) }}
{% else %}
{{ field(class=css_class, **kwargs) }}
{% endif %}
{% if field.errors %}
<ul class="errors">{% for error in field.errors %}<li>{{ error|e }}</li>{% endfor %}</ul>
{% endif %}
{% endmacro %}
usage is something like:
{{ field_with_errors(form.foo, placeholder='bar') }}
This lets me avoid boilerplate, but also lets me keep the display decisions in the template space.
Have a look at the rendering fields section.
Alternatively, you can add attributes to be rendered in the Jinja2 (etc.) template:
<div class="input-prepend">
{{ form.address(placeholder="example.com", id="address", autofocus="autofocus", required="required") }}
</div>
There's nothing to prevent you from using a variable for the ID value above, instead of address, then rendering the template with a keyword argument to populate it.

Categories