Django passing dictionary of tuples to template - python

If I made a set of code like this...
object_data = {}
object = Object.objects.all()
for o in object:
ratings = ObjectRating.objects.filter(recipe=r)
counter = 0
ratings_sum = 0
for s in ratings:
counter += 1
ratings_sum += s.rating
rating_average = ratings_sum / counter
object_data[`o.id`] = (o, rating_average,)
data = {
'search_by' : search_by,
'object' : object_data
}
If I pass the data dictionary to the page (render_to_response(page, data, context_instance=RequestContext(request))), how do I get the data from both parts of the tuple in the template.
This is how I thought I had to do it...
{% for o in object %}
<tr><td>{{ o.0.name }}</td><td>{{ o.0.description }}</td><td>{{ o.0.other_col }}</td><td>{{ o.0.another_col }}</td><td>{{ o.1 }}</td></tr>
{% endfor %}
This is driving me insane and any insight will be helpful. This is Django 1.6 (I know I need to move on, so do not mention that in your answer).

Why not just add rating_average as an attribute to your object?
for o in object:
... # calculate rating average for this object
o.rating_average = ratings_sum / counter
data = {
'search_by' : search_by,
'object' : object
}
{% for o in object %}
<tr><td>{{ o.name }}</td>
<td>{{ o.description }}</td>
<td>{{ o.other_col }}</td>
<td>{{ o.another_col }}</td>
<td>{{ o.rating_average }}</td>
</tr>
{% endfor %}

Like this example:
class HomeView(generic.TemplateView):
template_name = '_layouts/index.html'
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
mydict = {'wat': 'coo'}
context['mydict'] = mydict
return context
Template:
{% for key, value in mydict.items %}
{{ key }} : {{ value }}
{% endfor %}

Related

Python: Get multiple id's from checkbox

I wanted to get multiple id's from a list using checkbox. I got an error
Field 'id' expected a number but got [].
Below is my code.
sample.html
<button href="/sample/save">Save</button>
{% for obj in queryset %}
<tr>
<td><input type="checkbox" name="sid" value="{{obj.id}}"></td>
<td>{{ obj.sample_name }}</td>
<td>{{ obj.sample_type}}</td>
<td>{{ obj.number}}</td>
</tr>
{% endfor %}
views.py
def sample(request):
if request.method == 'GET':
queryset = SampleList.objects.all()
return render(request, 'lab_management/sample.html', {'queryset': queryset})
def save_doc(request):
sid = request.POST.getlist('sid')
sample = SampleList.objects.filter(id=sid)[0:10]
template = DocxTemplate("doc.docx")
context = {
'headers' : ['Name', 'Type', 'Number'],
'doc': [],
}
for samp in sample:
list = [samp.name, samp.type, samp.number]
context['doc'].append(list)
template.render(context)
template.save('new_doc.docx')
the field id should be int you passed a list, that's why you got error:
Field 'id' expected a number but got [].
Here you can use the in Filed lookup
Try this
sample = SampleList.objects.filter(id__in=sid)[0:10]
this will show all the SampleList items with the id's in sid
Update
Change your context to
context = {
'headers' : ['Name', 'Type', 'Number'],
'doc': sample,
}
then remove this for loop
# for samp in sample:
# list = [samp.name, samp.type, samp.number]
# context['doc'].append(list)
and in your template
{% for obj in doc %}
<tr>
<td><input type="checkbox" name="sid" value="{{obj.id}}"></td>
<td>{{ obj.name }}</td>
<td>{{ obj.type}}</td>
<td>{{ obj.number}}</td>
</tr>
{% endfor %}
NB: assuming name, type and number are the filed names of SampleList model

Building a dynamic table with jinja2, html and flask

<table style="width:100%", border="1">
{% for item in items %}
<tr>
<td>{{Description[item]}}</td>
<td>{{Location[item]}}</td>
<td>{{Status[item]}}</td>
</tr>
{% endfor %}
</table>
I am trying to create a table using this for loop, the variables are being passed through in the flask framework, 'items' will always be the same length as the three lists (Description, location and status).
I am aware of the question below:
How to build up a HTML table with a simple for loop in Jinja2?
but I can not see how my code here differs to the working answer to this question, is it because I am using a list instead of a dictionary ?
This is the flask framework, where the lists
are created an passed through using render template:
def index():
description = []
location = []
status = []
imix80m = ''
imix = ''
with open('behavepretty.json') as a:
data = json.load(a)
for n in range(0,len(data)):
i = 0
for i in range(0, len(data[n]['elements'])):
x = data[n]['elements'][i]['name']
description.append(x)
y = data[n]['elements'][i]['location']
location.append(y)
z = data[n]['elements'][i]['status']
status.append(z)
n = 0
for n in range(0,len(data)):
if n == 0:
imix80m = data[n]['status']
elif n == 1:
imix = data[n]['status']
a.close()
return render_template('trial.html', Description = description, Location= location, Status = status, result1 = imix80m, result2 = imix, jfile = data, items = description)
You just need a loop counter:
<table style="width:100%", border="1">
{% for item in Description %}
<tr>
<td>{{Description[loop.index0 ]}}</td>
<td>{{Location[loop.index0]}}</td>
<td>{{Status[loop.index0]}}</td>
</tr>
{% endfor %}
</table>
Or, you could pack the 3 into a list of lists:
my_list = [[Description0, Location0, Status0], [Description1, Location1, Status1], ...]
Then:
{% for item in my_list %}
<tr>
<td>{{ item[0] }}</td>
<td>{{ item[1] }}</td>
<td>{{ item[2] }}</td>
</tr>
{% endfor %}
Or, more robustly, a list of dictionaries:
my_list = [
{
"description" : xxx,
"location" : yyy,
"status" : zzz
},
{
"description" : www,
"location" : eee,
"status" : rrr
},
...
]
Then:
{% for item in my_list %}
<tr>
<td>{{ item.description }}</td>
<td>{{ item.location }}</td>
<td>{{ item.status }}</td>
</tr>
{% endfor %}

Creating multiple annotations using a for loop

Here is my code:
phones = Customer.objects.filter(active=True).values('name')\
.annotate(count = Count('phone',filter=Q(phone__model__icontains=model_list[0]))
.annotate(count1 = Count('phone',filter=Q(phone__model__icontains=model_list[1]))
.annotate(count2 = Count('phone',filter=Q(phone__model__icontains=model_list[2]))
.annotate(count3 = Count('phone',filter=Q(phone__model__icontains=model_list[3]))
.annotate(count4 = Count('phone',filter=Q(phone__model__icontains=model_list[4]))
........
html
{% if phones %}
{% for phone in phones %}
<tr>
<td>{{ phone.name }}</td>
<td>{{ phone.count }}</td>
<td>{{ phone.count1 }}</td>
<td>{{ phone.count2 }}</td>
<td>{{ phone.count3 }}</td>
<td>{{ phone.count4 }}</td>
</tr>
{% endfor %}
{% enfif %}
My model_list still has many models. What should I do to simplify these using for loop?
If my model_list has 100 models, this will be very complicated.
I've tried this:
for i in range(len(model_list)):
phone= Customer.objects.filter(active=True).values('name')\
.annotate(count = Count('phone',filter=Q(phone__model__icontains=model_list[i]))
html
{% if phones %}
{% for phone in phones %}
<tr>
<td>{{ phone.name }}</td>
<td>{{ phone.count }}</td>
</tr>
{% endfor %}
{% endif %}
But the result is not what I want, because I only get one of the data.
For example :model_list[0]
Do like this to query for counts:
phones = Customer.objects.filter(active=True).values('name')
for idx, model in enumerate(model_list):
counts = {'count%s' % idx : Count('phone',filter=Q(phone__model__icontains=model)}
phones = phones.annotate(**counts)
Then you would need to pass a range of models to the template (say in models_idx_range as context parameter models_idx_range=range(models_count)) and iterate over counts:
{% if phones %}
{% for phone in phones %}
<tr>
<td>{{ phone.name }}</td>
{% for idx in models_idx_range %}
<td>{{ getattr(phone, 'count%s' % idx) }}</td>
</tr>
{% endfor %}
{% endif %}
I'm not a django expert but i think this is your error:
phone = Customer.objects.filter(active=True).values('name')
for i in range(len(model_list)):
phone= phone.annotate(count = Count('phone',filter=Q(phone__model__icontains=model_list[i]))
You always override your phone with the last value from the for-loop
Try this one
phones = Customer.objects.filter(active=True).values('name')\
.annotate(count = Count('phone',filter=Q(phone__model__icontains=[i for i in model_list]))

print default value wtforms in jinja2

I'm using WTforms in Flask with Jinja2. I create a form like this:
def print_form(request, db):
class F(Form):
name = StringField('name', default='Mike')
video = SelectField(
'Programming Language',
choices=[('cpp', 'C++'), ('py', 'Python'), ('text', 'Plain Text')],default='py'
)
form1 = F(request.form)
data = {'form1' : form1}
rtemplate = jinja_env2.get_template('test.html')
data = rtemplate.render(**data)
Then I print the form in Jinja2 like this:
<table>
{% for field in form1 %}
<tr>
{% if field.type == "BooleanField" %}
<td></td>
<td>{{ field }} {{ field.label }}</td>
{% elif field.type == "HiddenField" %}
<td></td>
<td>{{ field }}</td>
{% elif field.type == "SelectField" %}
<td>{{ field.label }}</td>
<td>{{ field }}</td>
{% else %}
<td>{{ field.label }}</td>
<td>{{ field }}</td>
{% endif %}
</tr>
{% endfor %}
</table>
However I cannot find how to prefill the default value of the TextField, it's works automatically with the SelectField.

Django Forms: Get selected item from ModelChoiceField?

I'd like to access the selected item from a ModelChoiceField, similar to this:
forms.py
class ManageFeedsForms(forms.Form):
active_feed = forms.ModelChoiceField(queryset=Feed.objects.all(),
empty_label=None,
widget=forms.Select(attrs={'onchange': 'this.form.submit();'}),
)
def __init__(self, *args, **kwargs):
super(ManageFeedsForms, self).__init__(*args, **kwargs)
self.fields['active_feed'].label = ''
Template.html
{% for entry in feed_form.active_feed.selected_item.entry_list %}
<tr>
<td>{{ entry.title }}</td>
<td>{{ entry.date }}</td>
</tr>
{% endfor %}
views.py (very basic, just for testing)
def overview(request):
if request.GET:
form = ManageFeedsForms(request.GET)
if form.is_valid():
pass
else:
pass
else:
# Empty ManageFeedsForms
form = ManageFeedsForms()
return render_to_response('feed_management/home.html',
{'header_title': 'Feeds',
'feed_form' : form,
},
context_instance=RequestContext(request))
I'm looking for something like '.selected_item', so I can access the model's attributes.
Thanks for any help!
You should modify your view like so:
def overview(request):
selection = None
if request.GET:
form = ManageFeedsForms(request.GET)
if form.is_valid():
selection = form.cleaned_data['active_feed']
else:
# Empty ManageFeedsForms
form = ManageFeedsForms()
return render_to_response('feed_management/home.html',
{'header_title': 'Feeds',
'feed_form' : form,
'selection' : selection,
},
context_instance=RequestContext(request))
And your template:
{% if selection %}
<tr>
<td>{{ selection.title }}</td>
<td>{{ selection.date }}</td>
</tr>
{% endif %}

Categories

Resources